#include "Input_Handler.h"

#define DEFAULT_SHIFT   1
#define FAST_SHIFT      10
#define BIG_SHIFT       100


class Input_Handler_Cleaner {
public:
    ~Input_Handler_Cleaner() {
        Input_Handler::destroy();
    }
} Input_Handler_Cleaner_instance;

Input_Handler *Input_Handler::instance = NULL;


Input_Handler::Input_Handler() :
    leftPressed(false),
    rightPressed(false),
    upPressed(false),
    downPressed(false),
    m_status(0),
    m_x(0),
    m_y(0),
    m_lastx(0),
    m_lasty(0),
    m_layerList(*(Layer_List::get_instance())),
    m_currentCtx(*(CurrentContext::get_instance())),
    m_viewport(*(Viewport::get_instance()))
{
}

Input_Handler *Input_Handler::get_instance() {
    if(!instance) {
        instance = new Input_Handler();
        if (Debug::test(DEBUG_CREATE_DELETE)) {
            cout << "Input_Handler Created" << endl;
        }
    }
    return instance;
}

void Input_Handler::destroy() {
    if(instance) {
        delete instance;
        instance = NULL;
        if (Debug::test(DEBUG_CREATE_DELETE)) {
            cout << "Input_Handler destroyed" << endl;
        }
    }
}

void Input_Handler::input_handler_start() {
    int currentLayerId = INVALID_LAYER_ID;
    while(Viewport::keep_looping) {
        if( SDL_PollEvent( &event )) {
            switch( event.type ) {
                case SDL_MOUSEBUTTONDOWN:
                    if( event.button.button == SDL_BUTTON_LEFT ) {
                        m_x = event.button.x;
                        m_y = event.button.y;
                        if (Debug::test(DEBUG_INFO)) {
                            cout << "@@@@@Caught a mouse down at " << m_x << " " << m_y <<endl;
                        }
                        if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                            break;
                        }
                        Layer &l = m_layerList[currentLayerId];
                        if(l.makeSpriteAtXYActive(m_x + m_viewport.wx, m_y + m_viewport.wy)) {
                            m_lastx = m_x;
                            m_lasty = m_y;
                            m_status = HOLDING;
                        }
                    }
                    break;
                case SDL_MOUSEMOTION:
                    m_x = event.motion.x;
                    m_y = event.motion.y;
                    if(m_status == HOLDING) {
                        if (Debug::test(DEBUG_INFO)) {
                            cout << "@@@@@Mouse moved while holding " << endl;
                        }
                        if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                            break;
                        }
                        Layer &l = m_layerList[currentLayerId];
                        l.moveActiveSpritebyXY(m_x - m_lastx, m_y - m_lasty);
                        m_lastx = m_x;
                        m_lasty = m_y;
                    }
                break;
                case SDL_MOUSEBUTTONUP:
                    m_x = event.button.x;
                    m_y = event.button.y;

                    //If holding image
                    if( m_status == HOLDING ) {
                        if (Debug::test(DEBUG_INFO)) {
                            cout << "@@@@@Mouse up after holding at " << m_x << " " << m_y << endl;
                        }
                        if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                            break;
                        }
                        Layer &l = m_layerList[currentLayerId];
                        m_status = !HOLDING;
                        l.moveActiveSpritebyXY(m_x - m_lastx, m_y - m_lasty);
                    }
                break;
                case SDL_KEYDOWN:
                {
                    int disp = DEFAULT_SHIFT;
                    if (event.key.keysym.mod & KMOD_LSHIFT || event.key.keysym.mod & KMOD_RSHIFT) {
                        disp = FAST_SHIFT;
                    } else if (event.key.keysym.mod & KMOD_LCTRL || event.key.keysym.mod & KMOD_RCTRL) {
                        disp = BIG_SHIFT;
                    }

                    switch(event.key.keysym.sym) {
                        case SDLK_LEFT:
                            leftPressed = true;
                            m_viewport.decrement_wx(disp);
                            break;
                        case SDLK_RIGHT:
                            rightPressed = true;
                            m_viewport.increment_wx(disp);
                            break;
                        case SDLK_DOWN:
                            downPressed = true;
                            m_viewport.increment_wy(disp);
                            break;
                        case SDLK_UP:
                            upPressed = true;
                            m_viewport.decrement_wy(disp);
                            break;
                        case SDLK_ESCAPE:
                            Viewport::keep_looping = false;
                            break;
                        default:
                            break;
                    }
                    if(Debug::test(DEBUG_INFO)) {
                        cout << "VIEWPORT " << m_viewport.wx << " " << m_viewport.wy << endl;
                    }
                }
                    break;
                case SDL_KEYUP:
                    switch(event.key.keysym.sym) {
                        case SDLK_LEFT:
                            leftPressed = false;
                            break;
                        case SDLK_RIGHT:
                            rightPressed = false;
                            break;
                        case SDLK_DOWN:
                            downPressed = false;
                            break;
                        case SDLK_UP:
                            upPressed = false;
                            break;
                        case SDLK_KP_PLUS:
                            {
                                cout << "plus" << endl;
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                Layer &l = m_layerList[currentLayerId];
                                l.activeSpriteBringToFront();
                            }
                            break;
                        case SDLK_KP_MINUS:
                            {
                                cout << "minus" << endl;
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                Layer &l = m_layerList[currentLayerId];
                                l.activeSpriteSendToBack();
                            }
                            break;
                        case SDLK_v:
                            {
                                cout << "v" << endl;
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                Layer &l = m_layerList[currentLayerId];
                                l.activeSpriteToggleVisible();
                            }
                            break;
                        case SDLK_s:
                            {
                                cout << "s" << endl;
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                Layer &l = m_layerList[currentLayerId];
                                l.activeSpriteToggleSolid();
                            }
                            break;
                        case SDLK_DELETE:
                            {
                                cout << "Delete" << endl;
                                if ((currentLayerId = m_currentCtx.getCurrentLayerIndex()) == INVALID_LAYER_ID) {
                                    break;
                                }
                                Layer &l = m_layerList[currentLayerId];
                                l.activeSpriteDelete();
                            }
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
    }
}
